
package com.chuanke.ckfamily.service.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.chuanke.ckfamily.dao.base.CkUtil;
import com.chuanke.ckfamily.dao.finance.model.Bill;
import com.chuanke.ckfamily.dao.user.model.User;
import com.chuanke.ckfamily.service.common.CacheService;
import com.chuanke.ckfamily.service.common.model.RSAKey;
import com.chuanke.ckfamily.service.constant.Constant;
import com.chuanke.ckfamily.service.util.model.UserBalance;
import com.clusterswisdom.kid.server.libary.util.HttpUtil;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PropertiesLoaderUtils;

import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;

import java.io.*;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.security.*;
import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.util.*;

public class CkServerUtil {

    public static final String SIGN_INCOME = "WJ";

    private static final String RSA_KEY = "LOGIN_RSAKEY_KEY";

    private static final Logger logger = LoggerFactory.getLogger(CkServerUtil.class);

    public static final DecimalFormat userNoFormat = new DecimalFormat("gcf00000000");

    // 开发环境userNo
    private static final DecimalFormat userNoFormat_dev = new DecimalFormat("tgcf00000000");

    public static Boolean online;

    public static String HOST;

    public static String CKHOST;

    public static String API_USER;

    public static String API_FANS;

    public static String API_BALANCE;

    public static String API_CHARGE;

    public static String API_INCOME;

    static {
        Resource r = new ClassPathResource("/META-INF/host.properties");
        Properties props = null;
        try {
            props = PropertiesLoaderUtils.loadProperties(r);
            HOST = props.getProperty("host");
            CKHOST = props.getProperty("getkeyhost");
            API_USER = props.getProperty("api_user");
            API_FANS = props.getProperty("api_fans");
            API_BALANCE = props.getProperty("api_balance");
            API_CHARGE = props.getProperty("api_charge");
            API_INCOME = props.getProperty("api_income");
            online = props.getProperty("online").equals("true");

        } catch (Exception e) {
            e.printStackTrace();
            logger.debug("读取文件失败");
        }

    }


    public static User loadUser(Long uid) {
        Map<String, Object> param = new HashMap<>(1);
        param.put("uid", uid);

        JSONObject jsonObject = CkServerUtil.getCkData(API_USER, param);
        if (isSuccess(jsonObject)) {
            return formateUser(jsonObject.getJSONObject("userinfo"));

        } else {
            return null;

        }
    }

    public static List<User> loadFans(Long uid, int pageIndex) {
        Map<String, Object> param = new HashMap<>(3);
        param.put("uid", uid);
        param.put("start", pageIndex);
        param.put("limit", 50);
        JSONObject resultObj = CkServerUtil.getCkData(API_FANS, param);

        if (isSuccess(resultObj)) {
            JSONArray dataArray = resultObj.getJSONArray("data");
            List<User> userList = new ArrayList<>(dataArray.size());

            for (int i = 0; i < dataArray.size(); i++) {
                JSONObject dataItem = dataArray.getJSONObject(i);
                User user = CkServerUtil.formateUser(dataItem);
                userList.add(user);
            }

            return userList;

        } else {
            return null;

        }

    }

    public static UserBalance loadBalance(Long uid) {
        Map<String, Object> param = new HashMap<>(1);
        param.put("uid", uid);

        JSONObject json = CkServerUtil.getCkData(API_BALANCE, param);
        if (isSuccess(json)) {
            // 将返回的double值进行格式化返回
            UserBalance userBalance = new UserBalance();
            BigDecimal balance = json.getBigDecimal("userprice");
            if (balance == null) {
                balance = BigDecimal.ZERO;
            }
            balance = balance.multiply(new BigDecimal("100"));

            userBalance.setBalance(balance.longValue());
            userBalance.setTotal(json.getBigDecimal("totalprice").doubleValue());
            return userBalance;

        } else {
            return null;

        }
    }

    public static boolean charge(Long uid, Long money, CacheService cacheService) throws UnsupportedEncodingException {
        Map<String, Object> param = new HashMap<>(4);
        param.put("uid", uid);
        param.put("money", CkUtil.formateToYuan(money));
        param.put("type", 1);

        String sign = getSignIncome(param, cacheService);
        param.put("sign", URLEncoder.encode(sign, "UTF-8"));

        JSONObject json = CkServerUtil.getCkData(API_CHARGE, param);
        return isSuccess(json);
    }

    public static JSONObject getCkData(String url, Map<String, Object> param) {
        try {
            String responseContext = HttpUtil.getInstance().postHttpRequest(HOST + url, param);
            JSONObject resultObj = JSON.parseObject(responseContext);
            logger.debug("get ck url={}, param={}, data ={}", url, param, resultObj.toJSONString());
            if (resultObj.getInteger("code") != 0) {
                return null;
            }

            return resultObj;

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }

    // 收益到账
    public static Boolean uploadUserMoney(Bill bill, CacheService cacheService) throws IOException {
        Map<String, Object> param = new HashMap<>(6);
        param.put("uid", bill.getUid());
        param.put("money", (bill.getMoney() / 100.0));
        param.put("type", bill.getOptype());
        param.put("elect_id", bill.getFans_id());
        param.put("rid", bill.getId());

        String sign = getSignIncome(param, cacheService);
        param.put("sign", URLEncoder.encode(sign, "UTF-8"));
        return isSuccess(getCkData(API_INCOME, param));
    }

    /**
     * 格式化用户
     *
     * @param item
     * @return
     */
    private static User formateUser(JSONObject item) {
        logger.debug("json={}", item.toJSONString());
        String nickName = item.getString("nick_name");
        if (StringUtils.isEmpty(nickName)) {
            nickName = item.getString("wx_nickname");
        }
        Long id = item.getLong("id");
        if (StringUtils.isEmpty(nickName)) {
            nickName = "用户" + id;
        }

        User user = new User();
        user.setId(id);
        user.setNick_name(nickName);

        // 上级id 不能是自己
        Long elect_id = item.getLong("elect_id");
        if (elect_id != null && !elect_id.equals(id)) {
            user.setSuper_id(item.getLong("elect_id"));
        }

        user.setReal_name(item.getString("realname"));
        user.setPic(item.getString("wx_pic"));
        user.setFansNum(item.getInteger("elects"));
        user.setMobile(item.getString("mobile"));
        user.setAddress(item.getString("address"));

        String birthdday = item.getString("birthday");
        if (StringUtils.isNotEmpty(birthdday)) {
            try {
                Date birthDay = DateUtils.parseDate(birthdday, "yyyy-MM-dd");
                user.setBirthday(new Timestamp(birthDay.getTime()));
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }

        user.setIs_header(0);
        if (item.getInteger("wx_sex") == null) {
            user.setSex(0);

        } else {
            user.setSex(item.getInteger("wx_sex"));

        }

        Date date = item.getDate("registtime");
        if (date != null) {
            user.setCreate_time(new Timestamp(date.getTime()));
        }

        user.setUser_no(getUserNo(user.getId(), online));
        user.defaultValue();

        if (StringUtils.isEmpty(user.getPic())) {
            user.setPic(Constant.user_default_icon);
        }

//        if (StringUtils.isEmpty(user.getReal_name())) {
//            user.setReal_name(user.getNick_name());
//        }

        return user;
    }

    private static String getUserNo(Long uid, Boolean isTestEquipment) {
        if (isTestEquipment != null && isTestEquipment) {
            return userNoFormat.format(uid);
        } else {
            return userNoFormat_dev.format(uid);
        }
    }

    private static boolean isSuccess(JSONObject result) {
        if (result == null) {
            return false;
        }

        Integer code = result.getInteger("code");
        return code != null && code.intValue() == 0;
    }

    public static String getSignIncome(Map<String, Object> param, CacheService cacheService) {

        // 获取私钥
        RSAKey rsaKey = getRSAKey(cacheService);

        return encryptByPrivateKey(getRealSign(param).toString(), rsaKey.getKeyPair().getPrivate());

    }

    public static StringBuilder getRealSign(Map<String, Object> param) {
        StringBuilder contextBuilder = new StringBuilder();
        Iterator<Map.Entry<String, Object>> it = param.entrySet().iterator();
        List<String> lists = new ArrayList<>();
        while (it.hasNext()) {
            Map.Entry<String, Object> entry = it.next();
            if (entry.getValue() != null && !entry.getValue().toString().trim().equals("")) {
                lists.add(entry.getKey() + "=" + entry.getValue());
            }
        }
        Collections.sort(lists); // 排序
        Iterator<String> iterator = lists.iterator();
//        if(iterator.hasNext()){
//            contextBuilder.append(iterator.next()+"&");
//        }
        while (iterator.hasNext()) {
            contextBuilder.append(iterator.next() + "&");
        }
        contextBuilder.append("sign=" + SIGN_INCOME); // 最后在加盐 k=v&SIGN_INCOME
        logger.debug("upload user income sign -----------------> sign={}", contextBuilder.toString());
        return contextBuilder;
    }

    public static RSAKey getRSAKey(CacheService cacheService) {
        RSAKey rsaKey = (RSAKey) cacheService.get(RSA_KEY);
        if (rsaKey == null || rsaKey.getInvlidateTime() < System.currentTimeMillis() - 3600000) {
            rsaKey = createKey();
            cacheService.set(RSA_KEY, rsaKey);
        }

        return rsaKey;
    }

    public static RSAKey createKey() {
        KeyPairGenerator keyPairGen = null;
        try {
            keyPairGen = KeyPairGenerator.getInstance("RSA");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        keyPairGen.initialize(1024, new SecureRandom());
        KeyPair keyPair = keyPairGen.generateKeyPair();
        return new RSAKey(keyPair);
    }

    public static String encryptByPrivateKey(String data, PrivateKey privateKey) {
        try {
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);
            byte[] output = cipher.doFinal(data.getBytes("UTF-8"));
            return new BASE64Encoder().encodeBuffer(output);

        } catch (Exception e) {
            e.printStackTrace();
            return null;

        }
    }
}
